package taller2.controller.modes;

import java.awt.event.MouseEvent;

import javax.swing.JOptionPane;

import taller2.interfaces.Connection;
import taller2.interfaces.Graph;
import taller2.interfaces.Node;
import taller2.utils.Constants;
import taller2.utils.Point;
import taller2.utils.Utils;
import taller2.view.draws.DrawingArea;
import taller2.view.draws.GraphDrawer;

public class AddCapacityAndUseMode implements Mode{
	private Graph graph;
	
	// constructor
	public AddCapacityAndUseMode(Graph graph){
		this.graph = graph;
	}	
	
	// pressing the mouse button checks if there is a Node close enough
	// and selects it, to start moving it (but only if no other one is selected)
	public void whenPressed(MouseEvent arg0,DrawingArea area) {
		GraphDrawer drawer = area.getDrawer();
		Point pos = new Point(arg0.getX(),arg0.getY());
		
		if(drawer.noNodesSelected()){
			drawer.selectCloseByNode(pos);
		}else{
			int index1 = drawer.getSelectedNodeIndex();
			if(drawer.selectCloseByNode(pos)){
				int index2 = drawer.getSelectedNodeIndex();

				Node node1 = graph.getNodeByIndex(index1);				
				Node node2 = graph.getNodeByIndex(index2);

				Connection conn = node1.getConnectionTo(node2);
				
				node1.unselect();
				node2.unselect();

				if (conn != null){
				
					String cap = JOptionPane.showInputDialog ("Enter node capacity: "); 
					String use = JOptionPane.showInputDialog ("Enter node usage: "); 
					
					boolean balanced1 = false;	
					boolean balanced2 = false;	
					boolean areNotEmpty = (cap != null)&&(use != null);
					boolean areNumbers = Utils.isANumber(cap) && Utils.isANumber(use);
					
					if (areNumbers){
						balanced1 = balancedInputOutput(graph, conn, node1, Integer.parseInt(use));	
						balanced2 = balancedInputOutput(graph, conn, node2, Integer.parseInt(use));	
					}
					
					if (areNotEmpty && areNumbers && balanced1 && balanced2){
						int capacity = Integer.valueOf(cap);
						int usage = Integer.valueOf(use);
						boolean areValid = capacity >= usage;
						if(areValid){
							conn.setCapacity(capacity);
							conn.setFlux(usage);
							conn.setWeight(Constants.ConnectionKilled);
						}
					}
				}				
			}
		}
		
		area.repaint();
	}

	public void whenReleased(MouseEvent arg0,DrawingArea area) {}

	public void whenDragged(MouseEvent arg0,DrawingArea area) {}
	
	
	private boolean balancedInputOutput(Graph graph, Connection conn, Node node, int proposedFlux){
		//que el flujo de entrada y de salida sean iguales
		//se chequea solo cuando todas las otras aristas al nodo tienen ya flujo/capacidad asignadas
		//porque hasta que setean todas las aristas esta desbalanceado seguro
		//y solo si no es ni fuente ni sumidero
		
		int salidas,entradas;
		salidas = 0;
		entradas = 0;
		
		//que no sea fuente o sumidero; o el balance no importa y devuelvo true
		if ( (graph.getConnectionsTo(node).size() == 0) ||  (node.getConnections().size() == 0) ){
			return true;
		}
		
		boolean esEntrante =false;
		boolean esSaliente =false;
		
		//me fijo que sea la ultima arista a la que le falta flujo...
		int contAristasConFlujo = 0;
		
		//para las aristas entrantes
		for (Connection connAux : graph.getConnectionsTo(node)){
			
			if (connAux.getCapacity() != Constants.FluxConnKilled){
				contAristasConFlujo++;
				
				//ya me guardo la suma de flujos entrantes para no hacer el mismo recorrido despues
				entradas += connAux.getFlux();	
			}
			
			//la arista a la que le pongo el flujo entra a este nodo
			if (connAux == conn){
				esEntrante = true;
			}
		}
		
		//para las salientes
		for (Connection connAux : node.getConnections()){
			
			if (connAux.getCapacity() != Constants.FluxConnKilled){
				contAristasConFlujo++;
				
				//idem antes guardo flujo de salida
				salidas += connAux.getFlux();
			}
			
			//la arista a la que le pongo el flujo sale de este nodo
			if (connAux == conn){
				esSaliente = true;
			}
				
		}
		
		//si no estoy seteando la ultima devuelvo true
		int cantAristasTotales = graph.getConnectionsTo(node).size() + node.getConnections().size();
		if ( (contAristasConFlujo != cantAristasTotales - 1 ) || ( conn.getFlux() != Constants.FluxConnKilled ) ){
			return true;
		}
		
		//segun si es entrante o saliente el nuevo flujo cuenta como entrada o salida
		if (esEntrante){
			entradas += proposedFlux;
		}else if(esSaliente){
			salidas += proposedFlux;
		}
		
		if (entradas != salidas){
			return false;
		}else{
			return true;
		}
	}
}
